package iteratorbind.entity;

import iteratorbind.base.BaseMenuComponent;

import java.util.Iterator;
import java.util.Stack;

/**
 * 组合迭代器
 * 使用递归
 *这是一个外部的迭代器  有许多需要追踪的事情 外部迭代器必须维护它在遍历中的位置 以便外部客户可以通过调用hasNext()和Next()来驱动遍历
 * 当前例子中 我们的代码也必须维护组合递归结构的位置 这就是为什么当我们在组合层次结构中上上下下时,使用堆栈来维护我们的位置
 * @author yaojianfeng
 */
public class CompositeIterator implements Iterator {
    /**
     * 堆栈数据结构  将我们要遍历的顶层组合的迭代器传入
     * 我们把这个迭代器抛进去一个堆栈数据结构中
     */
    Stack stack = new Stack();

    public CompositeIterator(Iterator iterator) {
        stack.push(iterator);
    }

    @Override
    public boolean hasNext() {
        //想要知道是否还有下一个元素,我们检查堆栈是否被清空 如果空了就代表美原油下一个元素了
        if (stack.empty()) {
            return false;
        } else {
            //否则我们就从堆栈的顶层中取出迭代器 看看是否还有下一个元素 如果它没有元素 我们就弹栈 然后递归调用hasNext()
            Iterator peek = (Iterator) stack.peek();
            if (!peek.hasNext()) {
                stack.pop();
                return hasNext();
            } else {
                //否则 表示还有下一个元素 我们返回true
                return true;
            }
        }
    }

    /**
     * 取出下一个元素
     *
     * @return 组合对象
     */
    @Override
    public Object next() {
        if (hasNext()) {
            //如果还有下一个元素 我们就从堆栈中取出目前的迭代器 然后取得它的下一个元素
            Iterator peek = (Iterator) stack.peek();
            BaseMenuComponent next = (BaseMenuComponent) peek.next();
            //如果元素是一个菜单,我们有了另一个需要被包含进遍历中的组合 所以我们将它丢进堆栈中
            if (next instanceof MenuChildNode) {

                stack.push(next.getIterator());
            }
            //不管是不是菜单 我们都返回该组件
            return next;
        } else {
            //没有元素就返回null
            return null;
        }
    }

    /**
     * 我们不支持删除 这里只有遍历
     */
    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }
}
